#
# Copyright 2009 Red Hat, Inc. and/or its affiliates.
#
# Licensed to you under the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.  See the files README and
# LICENSE_GPL_v2 which accompany this distribution.
#

import threading
import logging

import misc

log = logging.getLogger("irs")

class RWLock(object):
    def __init__(self):
        self.w = threading.Lock()
        self.x = threading.Lock()
        self.r = threading.Lock()
        self.readers = 0

    def rlock(self, blocking=True):
        try:
            if not self.w.acquire(blocking):
                #log.debug("rlock: %s w lock failed" % self)
                return False
            # x can be blocking locked even if non blocking is requested because it is a short time lock
            self.x.acquire()
            self.r.acquire(False)
            self.readers += 1
            #log.debug("rlock: %s readers %s" % (self, self.readers))
            self.x.release()
            self.w.release()
            return True
        except:
            misc.panic("rlock %s blocking %s" % (self, blocking))

    def wlock(self, blocking=True):
        try:
            if not self.w.acquire(blocking):
                #log.debug("wlock: %s w lock failed" % self)
                return False
            if not self.r.acquire(blocking):
                self.w.release()
                #log.debug("wlock: %s r lock failed" % self)
                return False
            #log.debug("wlock: %s" % self)
            return True
        except:
            misc.panic("wlock %s blocking %s" % (self, blocking))

    def runlock(self):
        try:
            self.x.acquire()
            self.readers -= 1
            #log.debug("runlock: %s readers %s" % (self, self.readers))
            if self.readers == 0:
                self.r.release()
            elif self.readers < 0:
                log.error("runlock: %s readers %s!!!" % (self, self.readers))
            self.x.release()
        except:
            misc.panic("runlock %s" % (self))

    def wunlock(self):
        try:
            #log.debug("wunlock %s" % self)
            self.r.release()
            self.w.release()
        except:
            misc.panic("wunlock %s" % (self))

    def wcanlock(self):
        return self.wlock(blocking=False)

    def rcanlock(self):
        return self.rlock(blocking=False)
